package com.jackstraw.jack_base.remote_command.entity;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Data
@Slf4j
@Primary
@Component
@ConfigurationProperties(prefix = "jack.service")
public class JackServiceProperties {

    public final static String DEFAULT_CONNECT_NAME = "default";
    public final static String DEFAULT_CHART = "UTF-8";
    public final static String DEFAULT_IP = "localhost";
    public final static String DEFAULT_USER_NAME = "root";
    public final static String DEFAULT_PASSWORD = "root";
    public final static Integer DEFAULT_PORT = 22;
    public final static Long DEFAULT_TIMEOUT = 1000 * 60 * 10l;

    private Boolean enable = Boolean.TRUE;
    private String connectName;
    private String chart;
    private String ip;
    private Integer port;
    private String userName;
    private String password;
    private Long timeout;
    /**
     * 连接对应的配置文件
     */
    private String installPath;

    /**
     * 脚本控制
     * <p>
     * 若存在同时控制两套系统体系的情况下，请使用“软件名称-系统体系名称”命名，要求软件名称和系统体系名称中不允许出现“-”
     */
    private Map<String, JackSoftProperties> jackSoftPropertiesMap;

    /**
     * 字典
     */
    private Map<String, List<JackDictProperties>> jackDictPropertiesMap;

    private Map<String, Map<String, String>> jackDictMap;

    private Map<String, Map<String, String>> getJackDictMap() {
        return jackDictMap;
    }

    private JackServiceProperties setJackDictMap(Map<String, Map<String, String>> jackDictMap) {
        this.jackDictMap = jackDictMap;
        return this;
    }

    /**
     * 公共字典配置
     */
    private List<JackDictProperties> jackDictPropertiesList;


    private Boolean flag = Boolean.FALSE;


    private JackServiceProperties setFlag(Boolean flag) {
        this.flag = flag;
        return this;
    }

    private Boolean getFlag() {
        return flag;
    }

    public Map<String, Map<String, String>> resolverDictProperties() {
        Map<String, Map<String, String>> jackDictMap = new HashMap<>();
        if (ObjectUtils.isEmpty(this.jackDictPropertiesMap)) {
            this.jackDictPropertiesMap = new HashMap<>();
        }
        if (this.getFlag()) {
            return this.getJackDictMap();
        }
        this.setJackDictMap(jackDictMap);
        Map<String, String> jackDictPublicMap = new HashMap<>();
        if (ObjectUtils.isNotEmpty(this.getJackDictPropertiesList()) &&this.getJackDictPropertiesList().size() > 0) {
            jackDictPublicMap.putAll(this.getJackDictPropertiesList().stream()
                    .collect(Collectors.toMap(JackDictProperties::getDictName, JackDictProperties::getDictValue)));
        }
        this.jackDictPropertiesMap.forEach((key, value) -> {
            this.getJackDictMap().put(key,
                    value.stream().collect(Collectors.toMap(JackDictProperties::getDictName, JackDictProperties::getDictValue)));
            jackDictPublicMap.forEach((keyPublic, valuePublic) -> {
                if (!this.getJackDictMap().get(key).containsKey(keyPublic)) {
                    this.getJackDictMap().get(key).put(keyPublic, valuePublic);
                }
            });
        });
        this.setFlag(Boolean.TRUE);

        return this.getJackDictMap();
    }

    private Map<String, JackServiceProperties> servicePropertiesMap = new HashMap<>();

    public Map<String, JackServiceProperties> resolverProperties() {
        if (this.getServicePropertiesMap().size() == 0) {
            if (StringUtils.isEmpty(this.connectName)) {
                this.connectName = DEFAULT_CONNECT_NAME;
            }
            this.getServicePropertiesMap().put(this.connectName, this);
            return this.getServicePropertiesMap();
        }
        Map<String, JackServiceProperties> servicePropertiesMap = new HashMap<>();
        this.getServicePropertiesMap().forEach((key, value) -> {
            JackServiceProperties jackServiceProperties = new JackServiceProperties();
            BeanUtil.copyProperties(this, jackServiceProperties, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
            BeanUtil.copyProperties(value, jackServiceProperties, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
            BeanUtil.copyProperties(jackServiceProperties, value, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
            if (StringUtils.isEmpty(value.getConnectName())) {
                value.setConnectName(key);
            }
            if (!key.equals(value.getConnectName())) {
                log.warn("this connectName not equals map key");
            }
            if (StringUtils.isEmpty(value.getChart())) {
                value.setChart(DEFAULT_CHART);
            }
            if (StringUtils.isEmpty(value.getIp())) {
                value.setIp(DEFAULT_IP);
            }
            if (ObjectUtils.isEmpty(value.getPort())) {
                value.setPort(DEFAULT_PORT);
            }
            if (StringUtils.isEmpty(value.getUserName())) {
                value.setUserName(DEFAULT_USER_NAME);
            }
            if (StringUtils.isEmpty(value.getPassword())) {
                value.setPassword(DEFAULT_PASSWORD);
            }
            if (ObjectUtils.isEmpty(value.getTimeout())) {
                value.setTimeout(DEFAULT_TIMEOUT);
            }

        });
        return this.servicePropertiesMap;
    }

    public static String getIpByConnName(Map<String, JackServiceProperties> jackServicePropertiesMap, String connName) {
        JackServiceProperties jackServiceProperties = jackServicePropertiesMap.get(connName);
        if (ObjectUtils.isNotEmpty(jackServiceProperties)) {
            return jackServiceProperties.getIp();
        }
        return "";
    }
}
